package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.common.constants.message.NewsAutoScanConstants;
import com.heima.common.constants.message.WmNewsMessageConstants;
import com.heima.common.constants.wemedia.WemediaConstants;
import com.heima.common.exception.CustException;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.threadlocal.WmThreadLocalUtils;
import com.heima.model.wemedia.dtos.NewsAuthDto;
import com.heima.model.wemedia.dtos.WmNewsDto;
import com.heima.model.wemedia.dtos.WmNewsPageReqDto;
import com.heima.model.wemedia.pojos.WmMaterial;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmNewsMaterial;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.model.wemedia.vo.WmNewsVo;
import com.heima.wemedia.mapper.WmMaterialMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmNewsMaterialMapper;
import com.heima.wemedia.service.WmNewsService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;


@Service
@Slf4j
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {

    @Value("${file.oss.web-site}")
        String webSite;


    @Override
    public ResponseResult findList(WmNewsPageReqDto dto) {
        //检查参数(登录  分页)
        dto.checkParam();
        WmUser user = WmThreadLocalUtils.getUser();
        if (user == null) {
            CustException.cust(AppHttpCodeEnum.NEED_LOGIN);
        }
        //封装各种查询参数
        LambdaQueryWrapper<WmNews> queryWrapper = Wrappers.lambdaQuery();
        //标题  关键词模糊查询
        queryWrapper.like(StringUtils.isNoneBlank(dto.getKeyword()),WmNews::getTitle,dto.getKeyword());
        //频道
        queryWrapper.eq(dto.getChannelId() != null,WmNews::getChannelId,dto.getChannelId());
        //状态
        queryWrapper.eq(dto.getStatus() != null,WmNews::getStatus,dto.getStatus());
        //开始时间
        queryWrapper.ge(dto.getBeginPubDate() != null,WmNews::getPublishTime,dto.getBeginPubDate());
        //结束时间
        queryWrapper.le(dto.getEndPubDate() != null,WmNews::getPublishTime,dto.getEndPubDate());
        //当前登录用户id
        queryWrapper.eq(WmNews::getUserId,user.getId());
        //按照发布时间降序
        queryWrapper.orderByDesc(WmNews::getPublishTime);
        //分页查询
        IPage<WmNews> pageReq = new Page<>(dto.getPage(),dto.getSize());
        //执行查询  封装返回结果
        IPage<WmNews> pageResult = page(pageReq, queryWrapper);
        //将图片前缀访问路径设置到host属性中
        PageResponseResult responseResult = new PageResponseResult(dto.getPage(), dto.getSize(), pageResult.getTotal());
        responseResult.setData(pageResult.getRecords());
        responseResult.setHost(webSite);

        return responseResult;
    }

    @Autowired
    KafkaTemplate<String,String> kafkaTemplate;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public ResponseResult submitNews(WmNewsDto wmNewsDto) {
        //  检查参数   （封装wmNews对象）
        //检查参数内容  状态  是否登录
        if (StringUtils.isBlank(wmNewsDto.getContent())) {
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID,"文章内容不能为空");
        }
        Short status = wmNewsDto.getStatus();
        if (status == null || (status.intValue() != 0 && status.intValue() != 1)) {
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID,"文章状态错误");
        }
        WmUser user = WmThreadLocalUtils.getUser();
        if (user == null) {
            CustException.cust(AppHttpCodeEnum.NEED_LOGIN);
        }
        //基于dto创建wm_news
        WmNews wmNews = new WmNews();
        BeanUtils.copyProperties(wmNewsDto,wmNews);//拷贝属性
        //如果type=-1 将type暂时设置为null，避免保存错误
        if (wmNewsDto.getType().equals(WemediaConstants.WM_NEWS_TYPE_AUTO)) {
            wmNews.setType(null);
        }
        //如果传入的images集合不为空 转为字符串  用逗号拼接
        if (CollectionUtils.isNotEmpty(wmNewsDto.getImages())) {
            String imageStr = imageListToStr(wmNewsDto.getImages());
            wmNews.setImages(imageStr);
        }

        wmNews.setUserId(user.getId());
        //保存或修改WmNews
        saveOrUpdateWmNews(wmNews);
        //如果是待审核状态，需要保存  内容图片和封面图片与素材的关联关系
        if (status.intValue() == 0) {
            return ResponseResult.okResult();
        }
        // 抽取出内容中所涉及的所有图片
        List<String> contentImages = parseContentImages(wmNewsDto.getContent());
        //保存内容图片与素材的关联关系
        if (CollectionUtils.isNotEmpty(contentImages)) {
            saveRelativeInfo(contentImages,wmNews.getId(),WemediaConstants.WM_CONTENT_REFERENCE);
        }
        // 保存封面图片与素材的关联关系
        saveRelativeInfoCover(contentImages,wmNews,wmNewsDto);

        Map map = new HashMap();
        map.put("newId",wmNews.getId());
        kafkaTemplate.send(NewsAutoScanConstants.WM_NEWS_AUTO_SCAN_TOPIC, JSON.toJSONString(map));
        log.info("文章自动审核消息已成功发送，文章id:{}",wmNews.getId());
        //如果封面type为-1 需要基于内容图片生成封面图片
        return ResponseResult.okResult();
    }

    @Override
    public ResponseResult findWmNewsById(Integer id) {
        //检查id
        if (id == null) {
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID);
        }
        WmNews wmNews = getById(id);
        if (wmNews == null) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST,"文章信息不存在");
        }
        ResponseResult responseResult = ResponseResult.okResult(wmNews);
        responseResult.setHost(webSite);
        return responseResult;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public ResponseResult delNews(Integer id) {
        //检查id
        if (id == null) {
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID);
        }
        //根据id查询文章
        WmNews wmNews = getById(id);
        if (wmNews == null) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST,"文章信息不存在");
        }
        //判断文章状态是否为9，并且是否上架
        if (wmNews.getStatus().equals(WmNews.Status.PUBLISHED.getCode()) && wmNews.getEnable().equals(WemediaConstants.WM_NEWS_UP)) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_ALLOW,"该文章已发布，并且已上架，不能删除");
        }
        //删除文章以及文章与素材的关联关系
        removeById(id);
        wmNewsMaterialMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery().eq(WmNewsMaterial::getId,id));
        //返回结果
        return  ResponseResult.okResult();



    }

    @Override
    public ResponseResult downOrUp(WmNewsDto dto) {
        //检查参数（id  enable（0 1））
        if (dto.getId() == null || dto.getEnable() == null) {
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID);
        }
        Short enable = dto.getEnable();
        if (enable.intValue() != 0 && enable.intValue() != 1) {
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID,"上下架状态错误");
        }
        //根据id查询文章信息
        WmNews wmNews = getById(dto.getId());
        if (wmNews == null) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //检查文章状态是否为9（已发布）
        if (!wmNews.getStatus().equals(WemediaConstants.WM_NEWS_PUBLISH_STATUS)) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_ALLOW,"当前文章不是发布状态，无法上下架");
        }
        //修改wmnews 的enable字段
        wmNews.setEnable(enable);
        updateById(wmNews);

        if (wmNews.getArticleId() != null) {
            //发送消息，通知article微服务 ，进行对应的配置修改
            Map map = new HashMap();
            map.put("article",wmNews.getArticleId());
            map.put("enable",enable);
            kafkaTemplate.send(WmNewsMessageConstants.WM_NEWS_UP_OR_DOWN_TOPIC,JSON.toJSONString(map));
        }


        return ResponseResult.okResult();
    }

    @Override
    public ResponseResult<List<Integer>> findRelease() {
        //查询状态为4或8的数据，发布时间小于等于当前时间
        List<WmNews> list = list(Wrappers.<WmNews>lambdaQuery().in(WmNews::getStatus, 4, 8)
                .le(WmNews::getPublishTime, new Date())
                .select(WmNews::getId));
        List<Integer> newsIdList = list.stream().map(WmNews::getId).collect(Collectors.toList());
        return ResponseResult.okResult(newsIdList);
    }


    @Autowired
    WmNewsMapper wmNewsMapper;

    @Override
    public ResponseResult findList(NewsAuthDto dto) {
        //检查参数  分页  标题
        dto.checkParam();
        Integer currentPage = dto.getPage();
        dto.setPage((currentPage-1)*dto.getSize());
        //标题
        if (StringUtils.isNotBlank(dto.getTitle())) {
            dto.setTitle("%"+ dto.getTitle() +"%");
        }
        //调用mapper进行查询
        List<WmNewsVo> listAndPage = wmNewsMapper.findListAndPage(dto);
        long listCount = wmNewsMapper.findListCount(dto);
        //封装分页返回结果
        PageResponseResult responseResult = new PageResponseResult(currentPage, dto.getSize(), listCount);
        responseResult.setData(listAndPage);
        return responseResult;
    }

    @Override
    public ResponseResult findWmNewsVo(Integer id) {
        //检查
        if (id == null) {
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID,"id不能为空");
        }
        WmNewsVo wmNewsVo = wmNewsMapper.findWmNewsVoById(id);
        if (wmNewsVo == null) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST,"对应文章信息不存在");
        }
        ResponseResult responseResult = ResponseResult.okResult(wmNewsVo);
        responseResult.setHost(webSite);
        return responseResult;
    }

    @Override
    public ResponseResult updateStatus(Short status, NewsAuthDto dto) {
        //检查参数 id的值
        if (dto.getId() == null) {
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID,"文章id不能为空");
        }
        //根据id查询wmnews
        WmNews wmNews = getById(dto.getId());
        if (wmNews == null) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //修改wmNews状态
        wmNews.setStatus(status);
        if (StringUtils.isNotBlank(dto.getMsg())){
            wmNews.setReason(dto.getMsg());
        }
        updateById(wmNews);
        //返回结果
        return ResponseResult.okResult();
    }

    /**
     * 保存封面和素材的管理啊关系
     * @param contentImages
     * @param wmNews
     */
    private void saveRelativeInfoCover(List<String> contentImages, WmNews wmNews,WmNewsDto wmNewsDto) {
        List<String> images = wmNewsDto.getImages(); //封面的图片列表
        if (wmNewsDto.getType().equals(WemediaConstants.WM_NEWS_TYPE_AUTO)) {
            if (CollectionUtils.isEmpty(contentImages)) {
                wmNews.setType(WemediaConstants.WM_NEWS_NONE_IMAGE);
                images = null;
            }else if(contentImages.size() <= 2){
                wmNews.setType(WemediaConstants.WM_NEWS_SINGLE_IMAGE);
                images =  contentImages.stream().limit(1).collect(Collectors.toList());
            }else {
                wmNews.setType(WemediaConstants.WM_NEWS_MANY_IMAGE);
                images =  contentImages.stream().limit(3).collect(Collectors.toList());
            }
            if (CollectionUtils.isNotEmpty(images)) {
                wmNews.setImages(imageListToStr(images));
            }
            updateById(wmNews);
            }
        if (CollectionUtils.isNotEmpty(images)) {  //保存封面和素材的关联关系
            images = images.stream().map(url ->url.replaceAll(webSite,"")).collect(Collectors.toList());
            saveRelativeInfo(images,wmNews.getId(),WemediaConstants.WM_IMAGE_REFERENCE);
        }
        }
    @Autowired
    WmMaterialMapper wmMaterialMapper;
    /**
     *
     * @param materialUrls 相关素材URL集合
     * @param newsId  文章id
     * @param type  0 内容中引用的素材  1   封面引用的素材
     */
    private void saveRelativeInfo(List<String> materialUrls, Integer newsId, Short type) {
        //查询素材URL集合，所对应的所有素材信息
        List<WmMaterial> wmMaterials = wmMaterialMapper.selectList(Wrappers.<WmMaterial>lambdaQuery()
                .in(WmMaterial::getUrl, materialUrls)
                .eq(WmMaterial::getUserId, WmThreadLocalUtils.getUser().getId())
        );
        if (CollectionUtils.isEmpty(wmMaterials)) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST,"引用的素材不存在");
        }
        //将素材信息集合转为map集合  key: url  value : id
        Map<String, Integer> urlAndIdMap = wmMaterials.stream().collect(Collectors.toMap(WmMaterial::getUrl, WmMaterial::getId));
        //遍历素材URL集合，将每个URL对应的id存入到素材id中
        List<Integer> materialIds = new ArrayList<>();
        materialUrls.forEach(url ->{
            if (!urlAndIdMap.containsKey(url)) {
                CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST,"引用的素材不存在");
            }
            materialIds.add(urlAndIdMap.get(url));
        });
        //调用mapper 批量插入方法 id集合  newsid  type保存
        wmNewsMaterialMapper.saveRelations(materialIds,newsId,type);
    }
    /**
     * 抽取文章内容中所包含的所有图片，取出图片前缀
     * @param content 【{type:text ,value:文本内容}，{type：image，value：图片URL}，{}，{}】
     * @return
     */
    private List<String> parseContentImages(String content) {
        List<Map> contentMap = JSONArray.parseArray(content, Map.class);
        List<String> imageList = contentMap.stream()
                .filter(map -> WemediaConstants.WM_NEWS_TYPE_IMAGE.equals(map.get("type")))
                .map(map -> (String) map.get("value")) //获取map中value的值
                .map(url -> url.replaceAll(webSite, "")).
                collect(Collectors.toList());//将路径收集为集合
        return imageList;
    }

    @Autowired
    WmNewsMaterialMapper wmNewsMaterialMapper;

    /**
     * 保存或修改文章
     * @param wmNews
     */
    private void saveOrUpdateWmNews(WmNews wmNews) {
        //补全信息
        wmNews.setCreatedTime(new Date());
        wmNews.setSubmitedTime(new Date());
        wmNews.setEnable((short)1);
        //如果id为空   保存
        if (wmNews.getId() == null) {
            save(wmNews);
        }
        //如果id不为空  修改
        //删除关联关系
        wmNewsMaterialMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery().eq(WmNewsMaterial::getNewsId,wmNews.getId()));
        //修改文章
        updateById(wmNews);

    }


    /**
     * 将入参  封面集合  转为图片url字符串  替换前缀路径为空 使用逗号拼接
     * @param images
     * @return
     */
    private String imageListToStr(List<String> images) {
        return images.stream().
                map(str -> str.replaceAll(webSite, "")).
                collect(Collectors.joining(","));
    }
}
